/* (C) Copyright IBM Corp. 2010 */

package com.ibm.mining.sqldata;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;

import com.ibm.mining.*;
import com.ibm.team.repository.client.IItemManager;
import com.ibm.team.repository.common.*;
import com.ibm.team.workitem.common.model.IWorkItem;

public abstract class AbstractJazzItemHistoryInserter {
	MinerServices minerServices;

	public void setMinerServices(MinerServices minerServices) {
		this.minerServices = minerServices;
	}
	
	public List<JazzItemChange> getItemHistory(IAuditable item) throws TeamRepositoryException {
		List<JazzItemChange> changeList = new LinkedList<JazzItemChange>();
		JazzItemChange itemChange;
		
		IAuditableHandle olderItemHandle = item.getPredecessorState();
		while (olderItemHandle != null) {
			IAuditable olderItem;
			try {
			olderItem = (IAuditable) minerServices.getRepository().
				itemManager().fetchCompleteState(olderItemHandle, 
						minerServices.getMonitor());
			} catch (ItemNotFoundException e) {
				break;
			}
			String contributorUuid = null;
			if (item.getModifiedBy() != null) {
				contributorUuid = item.getModifiedBy().getItemId().getUuidValue();
			}
			itemChange = new JazzItemChange(contributorUuid, Util.dateToTimestamp(item.modified()));
			getChange(itemChange, olderItem, item);
			
			if (itemChange.numberOfPropertyChanges() > 0) {
				changeList.add(itemChange);
			}
			item = olderItem;
			olderItemHandle = item.getPredecessorState();
		}
		return changeList;
	}
	
	public void insertChange(JazzItemChange jic) throws SQLException {
		List<String> itemKeyList = new LinkedList<String>(jic.getItemKeys().keySet());
		String sql = "insert into " + jic.itemType + "_history " + 
			"(modified_by, modified, property, change_type, old_val, new_val, " + 
			Util.join(itemKeyList, ", ") + ") values (?, ?, ?, ?, ?, ?, " +
			Util.join(Util.repeat("?", itemKeyList.size()), ", ") + ")";
		
		PreparedStatement ps = minerServices.getResearchDatabase().conn.prepareStatement(sql);
		
		ps.setString(1, jic.modifiedBy);
		ps.setTimestamp(2, jic.modified);
		int i = 1;
		for(String key : itemKeyList) {
			ps.setString(6 + i, jic.itemKeys.get(key));
			i += 1;
		}
		for (JazzItemChange.PropertyChange propChange : jic.getPropertyChanges()) {
			ps.setString(3, propChange.property);
			ps.setString(4, propChange.changeType);
			ps.setString(5, propChange.oldVal);
			ps.setString(6, propChange.newVal);
			ps.execute();
		}
	}
	
	public abstract void getChange(JazzItemChange jic, IAuditable item, IAuditable newerItem)
		throws TeamRepositoryException;

	protected void addToChangeIfDifferentPrimitive(JazzItemChange jic, String attribute, Object oldVal, Object newVal) {
		if (oldVal == null) {
			if (newVal != null) {
				jic.addChange(attribute, "changed", null, newVal.toString());
			}
			return;
		}
		if (newVal == null) {
			if (oldVal != null) {
				jic.addChange(attribute, "changed", oldVal.toString(), null);
			}
			return;
		}
		if (!newVal.equals(oldVal)) {
			jic.addChange(attribute, "changed", oldVal.toString(), newVal.toString());
			return;
		}
	}

	protected void addToChangeIfDifferentModelClass(JazzItemChange jic, String attribute, Object oldVal, Object newVal) {
		if (oldVal == null) {
			if (newVal != null) {
				jic.addChange(attribute, "changed", null, newVal.toString());
			}
			return;
		}
		if (newVal == null) {
			if (oldVal != null) {
				jic.addChange(attribute, "changed", oldVal.toString(), null);
			}
			return;
		}
		if (!newVal.equals(oldVal)) {
			jic.addChange(attribute, "changed", oldVal.toString(), newVal.toString());
			return;
		}
	}

}
